#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include "playlist.h"
#include "getch.h"




playlist* _index(playlist* this, int id){
	
	if (id < 0){
		this = this->last(this);	
		for (; id; id++){
			if (this->previous(this))
				this = this->previous(this);
		}
	}
	else {
		this = this->first(this);
		for (; id>=0; id--){
			if (this->next(this))
				this = this->next(this);
		}
	}
	return this;
}

playlist* _next(playlist* this){
	if (this->fl->shuffle){
		int n = this->shuf;
		this = this->fl->first;
		while(this->shuf != n+1){
			//printf("sf: %d\n", this->shuf);
			this = this->_next;
			if (!this)
				break;
		}
		return this;
	}
		
	return this->_next;
}
playlist* _previous(playlist* this){
	if (this->fl->shuffle){
		int n = this->shuf;
		//printf("n: %d\n",n);
		this = this->fl->first;
		while(this->shuf != n-1){
			this = this->_next;
			if (!this)
				return this;
		}
		//printf("n: %d\n",this->shuf);
		return this;
	}	
	return this->_previous;
}

playlist* _insert(playlist* this,char* path){
	playlist *item = NULL;

	if (!this->first(this)->filename){
		//printf("* item is this!\n");
		item = this;
	}
	else{
		this = this->fl->last;
		item = malloc(sizeof(playlist));
		memset(item,0,sizeof(playlist));
		item->_previous = this;
		this->_next = item;
	}
	
	item->_next = NULL;
	item->fl = this->fl;
	item->fl->last = item;
	item->fl->count++;
	item->filename = malloc(strlen(path) +1);
	strcpy(item->filename,path);
	populate_methods(item);
	_reshufle(item);
	//dump_pl(item);
	return item;
	
}

playlist* _remove(playlist* this){
	playlist* next = this->_next;
	playlist* previous = this->_previous;
	if (! this->fl->count){
		//there is no more items on this list!
		return this;
	}
	//freeing items
	char* items[] = {
		this->filename,
		this->track,
		this->title,
		this->artist,
		this->album
	};
	int i;
	for ( i = 0; i < 5; i++) {
		if (items[i]){
			free(items[i]);
		}
	}
	if (this->fl->last == this){
		this->fl->last = this->_previous;
	}
	if (this->fl->first == this){
		this->fl->first = this;
	}
	this->fl->count--;
	
	free(this);
	if (previous)
		previous->_next = next;
	if (next)
		next->_previous = previous;
	_reshufle(previous);
	return previous? previous : next;
}

playlist* _first(playlist* this){
	if (this->fl->shuffle){
		this = this->fl->first;
		while (this->shuf != 0){
			this = this->_next;
		}
		return this;
	}
		
	else
		return this->fl->first;
} 
playlist* _last(playlist* this){
	if (this->fl->shuffle){
		
		this = this->fl->first;
		while (this->shuf != this->fl->count -1){
			this = this->_next;
		}
		return this;
	}
	else
		return this->fl->last;
} 

void populate_methods(playlist* this){
	this->first = _first;
	this->last = _last;
	this->next = _next;
	this->previous = _previous;
	this->insert = _insert;
	this->remove = _remove;
	this->index = _index;
	this->shuffle = _shuffle;
}

void _shuffle(playlist* this){
	this->fl->shuffle = !this->fl->shuffle;
	printf("The shuffle is %s\n", this->fl->shuffle? "Enabled": "Disabled");
	_reshufle(this);
}
void _reshufle(playlist* this){
	if (!this)
		return;
	if (!this->fl->count)
		return;
	
	if(this->fl->shuffle){
		srand(time(NULL));
		this = this->fl->first;
		int list[this->fl->count];
		int r,i;
		memset(list,0,this->fl->count * sizeof(int));

		while (this){
			r = rand() % this->fl->count;
			while (list[r]){
				r = (r+1) %  this->fl->count;
			}
			list[r]=1;

			
			this->shuf = r;
			this = this->_next;
		}
	}
	else{
		int n = 0;
		while(this){
			this->shuf = n++;
			this = this->_next;
		}
	}

}


playlist* create_playlist(){
	playlist* s = malloc(sizeof(playlist));
	s = memset(s,0,sizeof(playlist));
	s->fl = malloc(sizeof(playlist_fl));
	s->fl->first = s;
	s->fl->last = s;
	s->fl->shuffle = FALSE;
	s->fl->count = 0;
	populate_methods(s);
	
	return s;
}

void dump_pl(playlist* pl){
	printf("path: %s\n"
		   "shuffle: %d\n"
			"track: %s\n"
			"title: %s\n"
			"artist: %s\n"
			"album: %s\n"
			"next: %p\n"
			"previous: %p\n"
			"first: %p\n"
			"last: %p\n", 
				pl->filename,
				pl->shuf,
				pl->track,
				pl->title,
				pl->artist,
				pl->album,
				pl->next(pl),
				pl->previous(pl),
				pl->first(pl),
				pl->last(pl)
				);
}

playlist* playlist_argv(int argc, char* argv[]){
	playlist* pl = create_playlist();
	int i;
	for(i = 1; i < argc; i++){
		//printf("inserting %s\n", argv[i]);
		pl->insert(pl,argv[i]);
		
	}
	_reshufle(pl);
	return pl;
}

#ifdef D_RUN



int main(int argc, char* argv[]){
	int i = 0;
	char* shuffle[]={
		"==========\ndumping out the playlist without shuffle...\n\n\n",
		"==========\ndumping out the playlist with shuffle...\n\n\n",
		"==========\ndumping out AGAIN the playlist without shuffle...\n\n\n"
	};
	playlist* pl = create_playlist();
	playlist* tmp;
	for(i = 1; i < argc; i++){
		printf("inserting %s\n", argv[i]);
		pl = pl->insert(pl,argv[i]);
	}
	

	for(i = 0; i< 3; i++){
		tmp = pl;
		tmp = tmp->first(tmp);
		printf(shuffle[i]);
		fflush(stdout);
		dump_pl(tmp);
		
		while(tmp){
			printf("item %p\n",(tmp));
			dump_pl(tmp);
			tmp = tmp->next(tmp);				
		}
		pl->shuffle(pl);
		printf("pressione qualquer tecla");
		getch();
	}
	return 0;
}
	
	

	


#endif
